﻿using System;
using System.Data.SqlClient;
using System.Reflection;

namespace JTLeigh.Commerce.Spencer.Core.Testing
{

	/// <summary>
	/// Creates instances of <see cref="SqlException"/> for performing data tests.
	/// </summary>
	/// <remarks>
	/// <para>
	/// <see cref="SqlException"/> does not have a public constructor, so <see cref="SqlExceptionCreator"/>
	/// uses reflection to create instances using a non-public constructor.
	/// </para>
	/// </remarks>
	public static class SqlExceptionCreator
	{

		/// <summary>
		/// Creates an instance of <see cref="SqlException"/> representing a primary key violation.
		/// </summary>
		/// <returns>The <see cref="SqlException"/>.</returns>
		public static SqlException CreatePrimaryKeyViolation()
		{
			return Create(2627);
		}

		/// <summary>
		/// Creates an instance of <see cref="SqlException"/> with the specified error number.
		/// </summary>
		/// <param name="errorNumber">The error number.</param>
		/// <returns>The <see cref="SqlException"/>.</returns>
		/// <remarks>
		/// <para>
		/// The <see cref="SqlException"/> will contain a single <see cref="SqlError"/> whose
		/// error number is <paramref name="errorNumber"/> and whose other properties are not
		/// specified.
		/// </para>
		/// </remarks>
		public static SqlException Create(int errorNumber)
		{
			ConstructorInfo constructor;
			MethodInfo method;
			SqlErrorCollection errors;
			SqlError error;
			SqlException exception;

			constructor = typeof(SqlErrorCollection).GetConstructor((BindingFlags.NonPublic | BindingFlags.Instance), null, new Type[] { }, null);
			errors = (SqlErrorCollection)constructor.Invoke(new object[] { });

			constructor = typeof(SqlError).GetConstructor((BindingFlags.NonPublic | BindingFlags.Instance), null, new Type[] { typeof(int), typeof(byte), typeof(byte), typeof(string), typeof(string), typeof(string), typeof(int) }, null);
			error = (SqlError)constructor.Invoke(new object[] { errorNumber, (byte)0, (byte)10, "server", "message", "procedure", 0 });

			method = typeof(SqlErrorCollection).GetMethod("Add", (BindingFlags.NonPublic | BindingFlags.Instance));
			method.Invoke(errors, new object[] { error });

			constructor = typeof(SqlException).GetConstructor((BindingFlags.NonPublic | BindingFlags.Instance), null, new Type[] { typeof(string), typeof(SqlErrorCollection) }, null);
			exception = (SqlException)constructor.Invoke(new object[] { "This is a test SqlException created using SqlExceptionCreator.", errors });

			return exception;
		}

	}

}
